//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace OpenLS.UI.Internals
{
    public class GalleryPanel : Panel, IScrollInfo
    {
        private void onScrollChange()
        {
            if (ScrollOwner != null)
            {
                ScrollOwner.InvalidateScrollInfo();
            }
        }


        public int Columns
        {
            get { return (int)GetValue(ColumnsProperty); }
            set { SetValue(ColumnsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Columns.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColumnsProperty =
            DependencyProperty.Register("Columns", typeof(int), typeof(GalleryPanel), new FrameworkPropertyMetadata(2, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange, null, coerceValueCallback));

        private static object coerceValueCallback(DependencyObject d, object value)
        {
            int i = (int) value;
            return Math.Max(i, 0);
        }


        private int _rowCount;
       // private int _columnCount;
        Size _maxSize = new Size(0, 0);
        protected override Size MeasureOverride(Size availableSize)
        {
            //\\Debug.WriteLine("MeasureOverride " + GetType());
            _maxSize = new Size(1, 1);
            foreach (UIElement child in InternalChildren)
            {
                child.Measure(availableSize);
                _maxSize = new Size(Math.Max(child.DesiredSize.Width, _maxSize.Width),
                                    Math.Max(child.DesiredSize.Height, _maxSize.Height));
            }
            int columnCount = getColumnCount(availableSize.Width/_maxSize.Width);
            _rowCount = (int) Math.Ceiling(InternalChildren.Count/(double) columnCount);
            _visibleRowCount = availableSize.Height/_maxSize.Height;
            onScrollChange();
            return new Size(_maxSize.Width*columnCount, _maxSize.Height*_rowCount);
        }

        int getColumnCount (double ratio)
        {
            int result = Columns;
            if (result != 0)
                return result;
            result = (int) ratio;
            result = Math.Max(result, 1);
            return result;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            //\\Debug.WriteLine("MeasureOverride " + GetType());
            int rowIndex = -_verticalOffset;
            int columnIndex = 0;
            int columnCount = getColumnCount(finalSize.Width / _maxSize.Width);
            
            foreach (UIElement child in InternalChildren)
            {
                child.Arrange(new Rect(new Point(columnIndex * _maxSize.Width, rowIndex * _maxSize.Height), _maxSize));
                columnIndex++;
                if (columnIndex >= columnCount)
                {
                    columnIndex = 0;
                    rowIndex++;
                }
            }
            return finalSize;

        }

        private int _verticalOffset;
        private double _visibleRowCount;

        public void LineUp()
        {
            SetVerticalOffset(VerticalOffset - 1);
        }

        public void LineDown()
        {
            SetVerticalOffset(VerticalOffset + 1);
        }

        public void LineLeft()
        {
            throw new NotImplementedException();
        }

        public void LineRight()
        {
            throw new NotImplementedException();
        }

        public void PageUp()
        {
            SetVerticalOffset(VerticalOffset - _visibleRowCount);
        }

        public void PageDown()
        {
            SetVerticalOffset(VerticalOffset + _visibleRowCount);
        }

        public void PageLeft()
        {
            throw new NotImplementedException();
        }

        public void PageRight()
        {
            throw new NotImplementedException();
        }

        public void MouseWheelUp()
        {
            //Contract.Assert(false);
        }

        public void MouseWheelDown()
        {
           // Contract.Assert(false);
        }

        public void MouseWheelLeft()
        {
            // Contract.Assert(false);
        }

        public void MouseWheelRight()
        {
            throw new NotSupportedException();
        }

        public void SetHorizontalOffset(double offset)
        {
            throw new NotSupportedException();
        }

        public void SetVerticalOffset(double offset)
        {
            offset = Math.Min(Math.Ceiling( _rowCount - _visibleRowCount), offset);
            offset = Math.Max(offset, 0);
            _verticalOffset = (int)offset;
            InvalidateMeasure();
        }

        public Rect MakeVisible(Visual visual, Rect rectangle)
        {
            int index = findChildIndexThatParentsVisual(visual);
            double idealOffset = Math.Floor(index / (double)Columns);
          //  Debug.WriteLine("Make Visible" + VerticalOffset + " " + _visibleRowCount + " " + idealOffset);
            if (VerticalOffset > idealOffset)
                SetVerticalOffset(idealOffset);
            if (VerticalOffset + Math.Floor(_visibleRowCount) - 1 < idealOffset)
                SetVerticalOffset(idealOffset - Math.Floor(_visibleRowCount) + 1);
            return rectangle;
        }
        private int findChildIndexThatParentsVisual(DependencyObject child)
        {
            DependencyObject reference = child;
            DependencyObject parent = VisualTreeHelper.GetParent(child);
            while (parent != this)
            {
                reference = parent;
                parent = VisualTreeHelper.GetParent(reference);
                if (parent == null)
                {
                    throw new ArgumentException(("Stack_VisualInDifferentSubTree"), "child");
                }
            }
            return Children.IndexOf((UIElement)reference);
        }


        public bool CanVerticallyScroll { get; set; }

        public bool CanHorizontallyScroll { get; set; }

        public double ExtentWidth
        {
            get { return Columns; }
        }

        public double ExtentHeight
        {
            get
            {
                double result = _rowCount; // -_visibleRowCount;
               // result = Math.Max(result, 0);
                return result;
            }
        }

        public double ViewportWidth
        {
            get { return Columns; }
        }

        public double ViewportHeight
        {
            get { return _visibleRowCount; }
        }

        public double HorizontalOffset
        {
            get { return 0; }
        }

        public double VerticalOffset
        {
            get { return _verticalOffset; }
        }

        private ScrollViewer _scrollOwner;
        public ScrollViewer ScrollOwner
        {
            get { return _scrollOwner; }
            set { _scrollOwner = value; }
        }
    }
}
